Linux 源码中对 min,max 函数的宏实现 - sbw Blog

Linux 源码中对 min,max 函数的宏实现

来源: 石博文博客 | 浏览: 13903 | 评论: 0 发表时间: 2013-08-02

min、max等函数或宏定义是我们平时最常使用的,但往往没有更多的去思考它们的效率及其副作用。Linux内核代码有很多很经典的代码,仔细去看看,可以学到很多知识。下面让我们来看看,Linux 是如何实现它们的。



一般情况下,我们会定义这样的min,max宏:


1
2
#define min(x,y) ((x) > (y) ? (y) : (x))
#define max(x,y) ((x) > (y) ? (x) : (y))

表面来看,是没有任何问题的,但其实,这样的写法是有副作用的,例如,我们执行:


1
num = min(a,b++);

上面这句的本意是取a,b中的较小值,然后再把b+1,可是当编译时,宏展开之后,就成了下面的样子:


1
num = ((a) > (b++) ? (a) : (b++));

明显,b多加了一次.还有个缺陷就是不能进行类型检查,比如比较一个long型和一个int型,不会有提示,但很可能是程序写错.


在Linux源代码中,这样实现了min,max的宏:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#define min(x, y) ({                            \
         typeof(x) _min1 = (x);                  \
         typeof(y) _min2 = (y);                  \
         (void) (&_min1 == &_min2);              \
         _min1 < _min2 ? _min1 : _min2; })
   
#define max(x, y) ({                            \
         typeof(x) _max1 = (x);                  \
         typeof(y) _max2 = (y);                  \
         (void) (&_max1 == &_max2);              \
         _max1 > _max2 ? _max1 : _max2; })
   
#define min3(x, y, z) ({                        \
         typeof(x) _min1 = (x);                  \
         typeof(y) _min2 = (y);                  \
         typeof(z) _min3 = (z);                  \
         (void) (&_min1 == &_min2);              \
         (void) (&_min1 == &_min3);              \
         _min1 < _min2 ? (_min1 < _min3 ? _min1 : _min3) : \
                 (_min2 < _min3 ? _min2 : _min3); })
   
#define max3(x, y, z) ({                        \
         typeof(x) _max1 = (x);                  \
         typeof(y) _max2 = (y);                  \
         typeof(z) _max3 = (z);                  \
         (void) (&_max1 == &_max2);              \
         (void) (&_max1 == &_max3);              \
         _max1 > _max2 ? (_max1 > _max3 ? _max1 : _max3) : \
                 (_max2 > _max3 ? _max2 : _max3); })

这个看起来很复杂的宏,就完美的解决了我们遇到的问题,先来说说({}),这样的写法与c语言中的逗号表达式类似,其结果是取最后一个表达式的值.(({a;b;c;}) == c);其中typeof()操作符是gcc中取变量类型的操作符,比如下面的例子:


1
2
int a;
typeof(a) b; // b is int;

此时的变量b就是int型的.这样这个宏就很好理解了,它新建了两个变量保存原来的值,然后比较这两个副本,就可以避免上面的情况.


可是,宏中还有个很奇怪的语句,即(void) (&_min1 == &_min2); 这个语句的后半部分比较了两个变量的地址,当然我们不想知道这两个变量的地址是否相同,它存在的意义在于,当两个比较两个类型不同的变量的地址时,编译器会给出一个警告.提示我们在进行类型不同的比较.那么前面的(void)又是干什么用的呢?因为我们在比较两个地址之后并没有保存比较结果,编译器会认为这是一条无效语句,同样会给出一个警告.我们将它转换为(void)类型,编译器会认为我们对结果使用了,就不会提示这个错误.


在优化后,这个没有使用的结果会被优化掉,所以并不会拖慢程序,但新建的两个变量不会消除,它还是会有一点点的资源开销的,所以我觉得我们还是应该用前面那个简洁明了的方式定义宏,配合规范的'使用方法'来避免错误,要比费这么大力气搞这个宏要好的多.




没有人评论过此文,还不快抢个沙发
  • 昵称: *
  • 邮箱:
  • 网址:
  • 记住我的信息
  • Color
  • Red
  • Blue
  • Code
  • bash
  • cpp
  • css
  • java
  • js
  • perl
  • php
  • python
  • ruby
  • sql
  • xml